﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using DotNetCommon.Extensions;

namespace DotNetCommon.Encrypt
{
    /// <summary>
    /// DES加解密
    /// </summary>
    public static class DESEncrypt
    {

        /// <summary> 
        /// DES加密字符串 
        /// </summary> 
        /// <param name="encryptString">待加密的字符串</param> 
        /// <param name="encryptKey">加密密钥,必须为8位ASCII码,否则不成功</param> 
        /// <exception cref="Exception">加密过程失败</exception>
        /// <returns>加密后的字符串(16进制表示法)</returns> 
        public static string Encrypt(string encryptString, string encryptKey)
        {
            if (string.IsNullOrEmpty(encryptString)) return encryptString;
            if (string.IsNullOrWhiteSpace(encryptKey) || encryptKey.Length != 8) throw new Exception("秘钥的长度必须为8!");
            byte[] rgbKey = ASCIIEncoding.ASCII.GetBytes(encryptKey);

            byte[] rgbIV = ASCIIEncoding.ASCII.GetBytes(MD5Encrypt.MD5(encryptKey).Substring(0, 8));
            byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);

            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            des.Key = rgbKey;
            des.IV = rgbIV;
            MemoryStream mStream = new MemoryStream();
            CryptoStream cStream = new CryptoStream(mStream, des.CreateEncryptor(), CryptoStreamMode.Write);
            cStream.Write(inputByteArray, 0, inputByteArray.Length);
            cStream.FlushFinalBlock();
            StringBuilder ret = new StringBuilder();
            foreach (byte b in mStream.ToArray())
            {
                ret.AppendFormat("{0:X2}", b);
            }
            return ret.ToString();
        }
        /// <summary> 
        /// DES解密字符串 
        /// </summary> 
        /// <param name="decryptString">待解密的字符串</param> 
        /// <param name="decryptKey">加密密钥,必须为8位ASCII码,否则不成功</param> 
        /// <exception cref="Exception"></exception>
        /// <returns>解密后的字符串</returns> 
        public static string Decrypt(string decryptString, string decryptKey)
        {
            if (string.IsNullOrEmpty(decryptString)) return decryptString;
            if (string.IsNullOrWhiteSpace(decryptKey) || decryptKey.Length != 8) throw new Exception("秘钥的长度必须为8!");
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            int len;
            len = decryptString.Length / 2;
            byte[] inputByteArray = new byte[len];
            int x, i;
            for (x = 0; x < len; x++)
            {
                i = Convert.ToInt32(decryptString.Substring(x * 2, 2), 16);
                inputByteArray[x] = (byte)i;
            }

            byte[] rgbKey = ASCIIEncoding.ASCII.GetBytes(decryptKey);

            byte[] rgbIV = ASCIIEncoding.ASCII.GetBytes(MD5Encrypt.MD5(decryptKey).Substring(0, 8));

            des.Key = rgbKey;
            des.IV = rgbIV;
            MemoryStream mStream = new MemoryStream();
            CryptoStream cStream = new CryptoStream(mStream, des.CreateDecryptor(), CryptoStreamMode.Write);
            Byte[] inputByteArrays = new byte[inputByteArray.Length];
            cStream.Write(inputByteArray, 0, inputByteArray.Length);
            cStream.FlushFinalBlock();
            return Encoding.Default.GetString(mStream.ToArray());
        }

        /// <summary>
        /// 加密流,返回临时文件的路径
        /// </summary>
        /// <param name="stream">需要加密的流(自动将指针位置调整到0)</param>
        /// <param name="encryptKey">加密密钥,必须为8位ASCII码,否则不成功</param>
        /// <param name="tmpfiledir">临时文件目录</param>
        /// <exception cref="Exception"></exception>
        public static string Encrypt(Stream stream, string encryptKey, string tmpfiledir = null)
        {
            if (stream == null) throw new Exception("流不能为空!");
            if (string.IsNullOrEmpty(encryptKey)) throw new Exception("秘钥的长度必须为8!");
            if (string.IsNullOrWhiteSpace(encryptKey) || encryptKey.Length != 8) throw new Exception("秘钥的长度必须为8!");
            stream.Position = 0;
            byte[] rgbKey = ASCIIEncoding.ASCII.GetBytes(encryptKey);

            byte[] rgbIV = ASCIIEncoding.ASCII.GetBytes(MD5Encrypt.MD5(encryptKey).Substring(0, 8));

            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            des.Key = rgbKey;
            des.IV = rgbIV;

            string temppath = "";
            if (tmpfiledir.IsNullOrEmptyOrWhiteSpace())
            {
                temppath = System.IO.Path.GetTempPath();
                temppath = Path.Combine(temppath, "DotNetCommon.EncrptTemp");
            }
            else
            {
                temppath = tmpfiledir;
            }
            Directory.CreateDirectory(temppath);
            var guid = DateTime.Now.ToString("yyyyMMdd") + "_" + Guid.NewGuid().ToString();
            temppath = Path.Combine(temppath, guid);
            var fileStream = new FileStream(temppath, FileMode.Create);
            CryptoStream cStream = new CryptoStream(fileStream, des.CreateEncryptor(), CryptoStreamMode.Write);
            var bs = new byte[1024];
            var len = 0;
            do
            {
                len = stream.Read(bs, 0, bs.Length);
                cStream.Write(bs, 0, len);
            } while (len > 0);
            cStream.FlushFinalBlock();
            fileStream.Flush();
            fileStream.Close();
            return temppath;
        }

        /// <summary>
        /// 解密流，返回临时文件的路径
        /// </summary>
        /// <param name="stream">需要解密的流(自动将指针位置调整到0)</param>
        /// <param name="decryptKey">解密密钥</param>
        /// <param name="tmpfiledir">临时文件目录</param>
        public static string Decrypt(Stream stream, string decryptKey, string tmpfiledir = null)
        {
            if (stream == null) throw new Exception("流不能为空!");
            if (string.IsNullOrEmpty(decryptKey)) throw new Exception("秘钥的长度必须为8!");
            if (string.IsNullOrWhiteSpace(decryptKey) || decryptKey.Length != 8) throw new Exception("秘钥的长度必须为8!");
            byte[] rgbKey = ASCIIEncoding.ASCII.GetBytes(decryptKey);

            byte[] rgbIV = ASCIIEncoding.ASCII.GetBytes(MD5Encrypt.MD5(decryptKey).Substring(0, 8));

            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            des.Key = rgbKey;
            des.IV = rgbIV;

            string temppath = "";
            if (tmpfiledir.IsNullOrEmptyOrWhiteSpace())
            {
                temppath = System.IO.Path.GetTempPath();
                temppath = Path.Combine(temppath, "DotNetCommon.EncrptTemp");
            }
            else
            {
                temppath = tmpfiledir;
            }
            Directory.CreateDirectory(temppath);
            var guid = DateTime.Now.ToString("yyyyMMdd") + "_" + Guid.NewGuid().ToString();
            temppath = Path.Combine(temppath, guid);
            var fileStream = new FileStream(temppath, FileMode.Create);
            CryptoStream cStream = new CryptoStream(fileStream, des.CreateDecryptor(), CryptoStreamMode.Write);
            var bs = new byte[1024];
            var len = 0;
            do
            {
                len = stream.Read(bs, 0, bs.Length);
                cStream.Write(bs, 0, len);
            } while (len > 0);
            cStream.FlushFinalBlock();
            fileStream.Flush();
            fileStream.Close();
            return temppath;
        }
    }
}
